// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 包跟踪包含程序生成跟踪的工具
// 用于Go执行跟踪程序。
// 
// 跟踪运行时活动
// 
// 执行跟踪捕获范围广泛的执行事件，如
// GOROUTE创建/阻止/取消阻止、系统调用enter/exit/block、
// GC相关事件、堆大小更改、处理器启动/停止、，等。
// 对于大多数事件，都会捕获精确的纳秒级时间戳和堆栈跟踪。生成的跟踪可以使用“go tool trace”来解释
// 。
// 
// 支持使用标准
// 构建的跟踪测试和基准测试包内置在“go test”中。例如，下面的
// 命令在当前目录中运行测试，并写入跟踪
// 文件（trace.out）。
// 
// go test-trace=trace.out 
// 
// 此运行时/跟踪软件包提供API，用于向独立程序添加等效跟踪
// 支持。请参阅演示
// 如何使用此API启用跟踪的示例。
// 
// 还有一个用于跟踪数据的标准HTTP接口。添加
// 以下行将在/debug/pprof/trace URL下安装一个处理程序
// 以下载实时跟踪：
// 
// 导入u“net/http/pprof”
// 
// 有关此导入安装的所有
// 调试终结点的详细信息，请参阅net/http/pprof包。
// 
// 用户注释
// 
// 包跟踪提供用户注释API，可用于
// 记录执行期间的有趣事件。
// 
// 有三种类型的用户注释：日志消息、区域、
// 和任务。
// 
// Log向执行跟踪发送带时间戳的消息，以及
// 其他信息，如消息的类别和
// goroutine称之为Log。执行跟踪程序提供UI，以使用日志类别和日志中提供的消息
// 并对GORoutine进行分组。
// 过滤
// 
// 区域用于记录goroutine执行期间的时间间隔。
// 根据定义，一个区域在同一个goroutine中开始和结束。
// 可以嵌套区域以表示子区间。
// 例如，以下代码记录了执行过程中的四个区域
// 跟踪以跟踪卡布奇诺制作
// 操作中连续步骤的持续时间。
// 
// /trace.WithRegion（ctx，“makeCappuccino”，func（）{
// /
// /orderID允许在许多卡布奇诺订单区域记录中识别特定订单
// /trace.Log（ctx，“orderID”，orderID）
// 
// trace.WithRegion（ctx，“蒸汽牛奶”，蒸汽牛奶）
// trace.WithRegion（ctx，“提取咖啡”，提取咖啡）
// trace.WithRegion（ctx，“混合牛奶咖啡”，混合牛奶咖啡）
// ）
// 
// 任务是一个更高级别的组件，有助于跟踪逻辑
// 操作，如RPC请求、HTTP请求或
// 有趣的本地操作，可能需要多个Goroutine 
// 协同工作。由于任务可能涉及多个goroutine，
// 通过context.context对象跟踪它们。NewTask创建一个新任务并将其嵌入返回的context.context对象中。
// 在传递给Log and WithRegion的
// 上下文中将日志消息和区域附加到任务（如果有）。
// 
// 例如，假设我们决定将牛奶起泡，提取咖啡，
// 并将牛奶和咖啡混合在单独的goroutines中。通过一个任务，
// 跟踪工具可以识别特定
// 卡布奇诺订单中涉及的goroutine。
// 
// ctx，task:=trace.NewTask（ctx，“makeCappuccino”）
// trace.Log（ctx，“orderID”，orderID）
// 
// milk:=make（chan bool）
// espresso:=make（chan bool）
// 
// go func（）{
// trace.WithRegion（ctx，“蒸汽牛奶”，蒸汽牛奶）
// milk<-true 
// }（）
// go func（）{
// trace.WithRegion（ctx，“提取咖啡”，提取咖啡）
// espresso<-true 
// }（）
// go func（）{
// /延迟任务。结束（）
// <-espresso 
// <-牛奶
// /trace.WithRegion（ctx，“mixMilkCoffee”，mixMilkCoffee）
// /}（）
// 
// 
// 跟踪工具通过测量任务创建到任务结束之间的时间来计算任务的延迟，并为跟踪中找到的每个任务类型提供
// 延迟分布。
package trace

import (
	"io"
	"runtime"
	"sync"
	"sync/atomic"
)

// Start启用对当前程序的跟踪am.
// 在跟踪时，跟踪将被缓冲并写入w.
// 如果已启用跟踪，Start将返回一个错误。
func Start(w io.Writer) error {
	tracing.Lock()
	defer tracing.Unlock()

	if err := runtime.StartTrace(); err != nil {
		return err
	}
	go func() {
		for {
			data := runtime.ReadTrace()
			if data == nil {
				break
			}
			w.Write(data)
		}
	}()
	atomic.StoreInt32(&tracing.enabled, 1)
	return nil
}

// 停止当前跟踪（如果有）。
// 停止仅在跟踪的所有写入操作完成后返回。
func Stop() {
	tracing.Lock()
	defer tracing.Unlock()
	atomic.StoreInt32(&tracing.enabled, 0)

	runtime.StopTrace()
}

var tracing struct {
	sync.Mutex       // 门突变器（启动、停止）
	enabled    int32 // 通过原子
}
